package org.jheuristics.ga.operators.selectors.roulettes;

import org.epanetgrid.otimizacao.log.AGLogger;
import org.jheuristics.ga.operators.selectors.Roulette;
import org.jheuristics.util.MathUtils;
import org.jheuristics.util.RandomGenerator;


/**
 * TODO
 *
 * @author Marcell Manfrin, marcell@ourgrid.org, Jan 9, 2006
 */
public abstract class AbstractRoulette implements Roulette {
	private RandomGenerator random;
	private double[] probabilities;

	/**
	 * TODO
	 *
	 * @param probabilities
	 * @param deltaSpin
	 */
	public AbstractRoulette(double[] values, RandomGenerator random) {
		verifyValues(values);
		verifyRandom(random);
		initialize(values, MathUtils.min(values), random);
	}

	/**
	 * TODO
	 *
	 * @param values
	 * @param minimalValue
	 * @param deltaSpin
	 */
	public AbstractRoulette(double[] values, double minimalValue, RandomGenerator random) {
		verifyValues(values);
		verifyRandom(random);
		verifyMinimalValue(values, minimalValue);
		initialize(values, minimalValue, random);
	}

	/**
	 * TODO
	 *
	 * @param howMany
	 * @return
	 * @see org.jheuristics.ga.operators.selectors.Roulette#spin(int)
	 */
	public int[] spin(int howMany) {
		if (0 > howMany) {
			// TODO: MSG
			throw new IllegalArgumentException();
		}
		return null;
	}

	/**
	 * TODO
	 *
	 * @return
	 */
	public RandomGenerator getRandom() {
		return random;
	}

	/**
	 * TODO
	 *
	 * @param random
	 */
	public void setRandom(RandomGenerator random) {
		verifyRandom(random);
		this.random = random;
	}

	/**
	 * TODO
	 *
	 * @return
	 */
	protected double[] getProbabilities() {
		return probabilities;
	}

	/**
	 * TODO
	 *
	 * @param values
	 * @param minimal
	 * @param random
	 */
	private void initialize(double values[], double minimal, RandomGenerator random) {
		this.random = random;
		probabilities = calculateProbabilities(values, minimal);
		
		StringBuffer buffer = new StringBuffer("Prob. Sele��o Acumulada: \n");
		for (int i = 0; i < probabilities.length; i++) {
			buffer.append(i+1);
    		buffer.append(". ");
    		buffer.append(probabilities[i]);
    		buffer.append("\n");
		}
		
		AGLogger.getInstance().debug(buffer);
	}

	/**
	 * TODO
	 *
	 * @param values
	 * @return
	 */
	private double[] calculateProbabilities(double values[], double minimalValue) {
		double[] probabilities = new double[values.length];
		for (int i = 0; i < probabilities.length; i++) {
			probabilities[i] = (values[i] - minimalValue);
		}
		double sum = MathUtils.sum(probabilities);
		probabilities[0] = probabilities[0] / sum;
		probabilities[probabilities.length-1] = 1.0;
		for (int i = 1; i < probabilities.length - 1; i++) {
			probabilities[i] = probabilities[i-1] + (probabilities[i] / sum);
		}
		return probabilities;
	}

	/**
	 * TODO
	 *
	 * @param values
	 */
	private void verifyValues(double[] values) {
		if (null == values) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
		if (0 == values.length) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
		}
	}

	/**
	 * TODO
	 *
	 * @param deltaSpin
	 */
	private void verifyRandom(RandomGenerator random) {
		if (null == random) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
	}

	/**
	 * TODO
	 *
	 * @param values
	 * @param minimal
	 */
	private void verifyMinimalValue(double[] values, double minimal) {
		for (int i = 0; i < values.length; i++) {
			if (minimal > values[i]) {
				// TODO: ERROR MSG
				throw new IllegalArgumentException();
			}
		}
	}

}
